package code.jam.context;

import java.io.File;
import java.io.IOException;
import java.util.Vector;
import my.andoird.util.r1.AndroidString;
import my.andoird.util.r1.JamThread;
import code.jam.core.JamDataManager;
import code.jam.core.JamNoteBuffer;
import code.jam.core.JamParser;
import code.jam.interfaces.JamBGMListener;
import android.media.MediaPlayer;
import android.util.Log;

public class JamBGMContext implements JamBGMListener
{
	public static final String		DEBUG_TAG			= "JamBGMContext";
	public static final String		THREAD_NAME			= "JAM_BGM_CONTEXT_THREAD";

	private int						scale[]				= null;
	private float					tempo				= 0.0f;
	private int						accent[]			= null;
	private MediaPlayer				media_player		= null;
	private int						temp_pos			= 0;
	private JamMIFContext			mif_context			= null;
	private JamAdditionalBGMContext	current_bgm_context	= null;
	private String					title				= null;
	private String					bgm_file_name		= null;
	private String					mif_file_name		= null;
	private float					volume				= 0.5f;
	int								chord_array[]		= null;
	boolean							is_bgm_thread_alive	= true;
	Thread							bgm_thread			= null;
	JamBGMListener					bgm_listener		= null;
	private int						chord_length		= 0;
	private int						volume_length		= 0;
	
	private String current_chord = null;
	public boolean	is_stopped = true;

	public JamBGMContext(String title, String bgm_file_name, String mif_file_name)
	{
		super();

		this.title = title;
		this.bgm_file_name = bgm_file_name;
		this.mif_file_name = mif_file_name;
		
		this.current_chord = new String();

		initialize();
	}

	public void addListener(JamBGMListener listner)
	{
		bgm_listener = listner;

		bgm_thread = new Thread(new Runnable()
		{
			public void run()
			{
				while (is_bgm_thread_alive == true)
				{
					bgm_listener.onChangeChordProgression(getCurrentPlayingTime());
					bgm_listener.onChangeGlobalVolume(getCurrentPlayingTime());

					JamThread.sleep(10);
				}
			}
		}, THREAD_NAME);

		bgm_thread.start();
	}

	private void initialize()
	{
		initializeMIFContext();
		initializeCurrentBGMContext();
	}

	private void initializeCurrentBGMContext()
	{
		Vector<Integer> accents = mif_context.getAccent();

		int accent_array[] = new int[accents.size()];

		for (int i = 0; i < accent_array.length; i++)
		{
			accent_array[i] = accents.elementAt(i).intValue();
		}

		setAccent(accent_array);

		setTempo(mif_context.getTempo().floatValue());

		String scale = mif_context.getScale();

		int scale_array[] = JamChord.searchScale(scale);

		setScale(scale_array);

		if (current_bgm_context == null)
		{
			this.current_bgm_context = new JamAdditionalBGMContext(this);
		}

		return;
	}

	private void initializeMediaPlayer()
	{
		String absolute_path = JamURI.JAM_SD_BGM_PATH + File.separator + this.bgm_file_name;

		try
		{
			media_player = new MediaPlayer();
			media_player.setDataSource(absolute_path);
			media_player.prepare();
			media_player.setVolume(volume, volume);
		}
		catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch (IllegalStateException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		return;
	}

	public void initializeMIFContext()
	{
		String string = JamDataManager.readTextFromSD(JamURI.JAM_SD_MIF_PATH, this.mif_file_name);

		if (AndroidString.isEmpty(string))
		{
			Log.e(DEBUG_TAG, "can't read MIF file");

			return;
		}

		JamMIFContext mif_context = JamParser.parseMIF(string);

		this.mif_context = mif_context;

		if (mif_context == null)
		{
			Log.e(DEBUG_TAG, "can't parse mif file : " + this.mif_file_name);
		}

		return;
	}

	public JamAdditionalBGMContext getAdditionalBGMContext()
	{
		return this.current_bgm_context;
	}

	public JamMIFContext getMIFContext()
	{
		return mif_context;
	}
	
	public String getCurrentChord()
	{
		return current_chord;
	}

	public boolean isPlaying()
	{
		boolean b = false;
		
		if( is_stopped == true)
			b = false;
		else 
			b = media_player.isPlaying();
	
		return b;
	}

	public boolean isLooping()
	{
		return this.media_player.isLooping();
	}

	public void setLooping(boolean loop)
	{
		this.media_player.setLooping(loop);
	}

	public void setVolume(float volume)
	{
		media_player.setVolume(volume, volume);
	}

	public void play()
	{
		is_stopped 			= false;
		is_bgm_thread_alive = true;
		
		initializeMediaPlayer();
		addListener(this);
		media_player.start();
	}

	public void pause()
	{
		this.media_player.pause();
	}
	
	public boolean isStopped()
	{
		return is_stopped;
	}
	
	public void drop()
	{
		is_stopped 			= true;
		is_bgm_thread_alive = false;
		bgm_thread 			= null;
		chord_length 		= 0;
		
		if (this.media_player != null)
		{
			try
			{
				media_player.stop();
			}
			catch (IllegalStateException e)
			{
				e.printStackTrace();
			}
			finally
			{
				media_player.release();
				media_player = null;
				
				Log.d(DEBUG_TAG, "MediaPlayer is dropping...");
			}
		}
	}

	public String getTitle()
	{
		return title;
	}

	public void setTitle(String audio_name)
	{
		title = new String(audio_name);
	}

	public void setJamMifContext(JamMIFContext mif_context)
	{
		this.mif_context = mif_context;
	}

	public int getCurrentPlayingTime()
	{
		int ret = 0;
		
		if( is_stopped == false)
		{
			ret =  media_player.getCurrentPosition();
		}
		
		return ret;
	}

	public String getNoteOnTime()
	{
		if (mif_context == null)
		{
			return null;
		}

		String mif_chord = null;

		int current_playing_time = getCurrentPlayingTime();

		Vector<JamChordProgressionContext> vector = this.mif_context.getChordProgression();

		int mif_time = vector.get(this.temp_pos).getTime();

		if (current_playing_time == mif_time)
		{
			this.temp_pos++;
		}

		mif_chord = new String(vector.get(this.temp_pos).getChord());

		return mif_chord;
	}

	public int getWholeDuration()
	{
		int ret = 0;
		
		if(is_stopped == false)
			ret = media_player.getDuration();
		
		return ret;
	}

	public JamNoteBuffer getNoteBuffer()
	{
		if (this.current_bgm_context != null)
		{
			return this.current_bgm_context.getNoteBuffer();
		}

		return null;
	}

	public int[] getScale()
	{
		return scale;
	}

	public void setScale(int[] scale)
	{
		this.scale = scale;
	}

	public float getTempo()
	{
		return tempo;
	}

	public void setTempo(float tempo)
	{
		this.tempo = tempo;
	}

	public int[] getAccent()
	{
		return accent;
	}

	public void setAccent(int[] accent)
	{
		this.accent = accent;
	}

	public void onChangeChordProgression(int current_time)
	{
		int band = (((int) (getTempo() * 1000) / 60) / 32);

		Vector<JamChordProgressionContext> chords = getMIFContext().getChordProgression();
		int chords_length = chords.size();

		if (chord_length < chords_length)
		{
			JamChordProgressionContext current_chord_context = chords.elementAt(chord_length);

			boolean b = (current_time > (current_chord_context.getTime() - band)) && (current_time < (current_chord_context.getTime() + band));

			if (b)
			{
				chord_length++;
				
				current_chord = new String(current_chord_context.getChord());

				chord_array = JamChord.searchChordProgression(current_chord_context.getChord());
			}
		}

		if (chord_array != null)
		{
			if (current_time > current_bgm_context.getRhythme_error())
			{
				current_bgm_context.applyNoteBuffer(current_time - current_bgm_context.getRhythme_error(), chord_array[0], chord_array[1]);
			}
			else
			{
				current_bgm_context.applyNoteBuffer(current_time - current_bgm_context.getRhythme_error(), chord_array[0], chord_array[1]);
			}
		}
	}

	public void onChangeGlobalVolume(int current_time)
	{
		final Vector<JamGlobalVolumeContext> global_volumes = mif_context.getGlobalVolume();
		final int volumes_length = global_volumes.size();

		if (volume_length < volumes_length)
		{
			int length_limit = 0;

			JamGlobalVolumeContext global_volume_context = global_volumes.elementAt(volume_length);
			
//			Log.d(DEBUG_TAG, String.format("%d : %d", global_volume_context.getTime(), global_volume_context.getGlobalVolume()));

			if (volume_length + 1 >= volumes_length)
			{
				length_limit = volume_length;
			}
			else
			{
				length_limit = volume_length + 1;
			}

			boolean b = (current_time > global_volumes.elementAt(volume_length).getTime())
					&& (current_time < global_volumes.elementAt(length_limit).getTime());

			if (b)
			{
				if (volumes_length > volume_length)
				{
					volume_length++;
				}

				current_bgm_context.setGlobalVolume(global_volume_context.getGlobalVolume());

			}
		}
	}
}
